#include <trap.h>
#include <env.h>
#include <printf.h>
#include <types.h>
#include <mmu.h>

extern void handle_int();
extern void handle_reserved();
extern void handle_tlb();
extern void handle_sys();
extern void handle_mod();
u_ptr64_t exception_handlers[32];

void trap_init()
{
    int i;

    for (i = 0; i < 32; i++) {
        set_except_vector(i, handle_reserved);
    }

    set_except_vector(0, handle_int);
    set_except_vector(1, handle_mod);
    set_except_vector(2, handle_tlb);
    set_except_vector(3, handle_tlb);
    set_except_vector(8, handle_sys);
}
void *set_except_vector(int n, void *addr)
{
    u_int64_t handler = (u_int64_t)addr;
    u_int64_t old_handler = exception_handlers[n];
    exception_handlers[n] = handler;
    return (u_ptr64_t)old_handler;
}


struct pgfault_trap_frame {
    u_int64_t fault_va;
    u_int64_t err;
    u_int64_t sp;
    u_int64_t eflags;
    u_int64_t pc;
    u_int64_t empty1;
    u_int64_t empty2;
    u_int64_t empty3;
    u_int64_t empty4;
    u_int64_t empty5;
};


/*** exercise 4.11 ***/
void
page_fault_handler(struct Trapframe *tf)
{                                  // ^ tf is sp (see lib/genex.S)
    struct Trapframe PgTrapFrame;
    extern struct Env *curenv;
//printf("traps.c: page_fault_handler\n");
    bcopy(tf, &PgTrapFrame, sizeof(struct Trapframe));

    if (tf->regs[2] >= (curenv->env_xstacktop - BY2PG) &&
        tf->regs[2] <= (curenv->env_xstacktop - 1)) {
            tf->regs[2] = tf->regs[2] - sizeof(struct  Trapframe);
            bcopy(&PgTrapFrame, (void *)tf->regs[2], sizeof(struct Trapframe));
        } else {
            tf->regs[2] = curenv->env_xstacktop - sizeof(struct  Trapframe);
            bcopy(&PgTrapFrame,(void *)curenv->env_xstacktop - sizeof(struct Trapframe), sizeof(struct Trapframe));
        }
    // Set EPC to a proper value in the trapframe
    tf->epc = curenv->env_pgfault_handler;
//test_vaddr_map(curenv->env_vpt2, 0x7f3fd000, 0x7f3fd000);
//printf("traps.c: end\n");
    return;
}

void perm_error(u_int64_t pte)
{
	printf("Perm error!\nPerm: ");
	if ((pte & PTE_V) != 0) {
		printf("Valid ");
	}
	if ((pte & PTE_R) != 0) {
		printf("Read ");
	}
	if ((pte & PTE_W) != 0) {
		printf("Write ");
	}
	if ((pte & PTE_X) != 0) {
		printf("Execute ");
	}
	if ((pte & PTE_U) != 0) {
		printf("User ");
	}
	if ((pte & PTE_COW) != 0) {
		printf("Copy_On_Write ");
	}
	if ((pte & PTE_LIBRARY) != 0) {
		printf("Library ");
	}
	printf("\n");
	panic("PERM ERROR!!!!");
}
